package com.yunxi.module.system.service.dict.impl;

import cn.hutool.core.collection.CollUtil;
import com.google.common.annotations.VisibleForTesting;
import com.yunxi.framework.common.enums.CommonStatusEnum;
import com.yunxi.framework.common.exception.util.ServiceExceptionUtil;
import com.yunxi.framework.common.pojo.PageResult;
import com.yunxi.framework.common.util.collection.CollectionUtils;
import com.yunxi.framework.common.util.object.BeanUtils;
import com.yunxi.module.system.enums.constant.ErrorCodeConstants;
import com.yunxi.module.system.mapper.dict.DictDataMapper;
import com.yunxi.module.system.model.dict.DictDataDO;
import com.yunxi.module.system.model.dict.DictTypeDO;
import com.yunxi.module.system.service.dict.DictDataService;
import com.yunxi.module.system.service.dict.DictTypeService;
import com.yunxi.module.system.vo.admin.dict.data.DictDataPageReqVO;
import com.yunxi.module.system.vo.admin.dict.data.DictDataSaveReqVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 字典数据 Service 接口实现类
 * </p>
 *
 * @author lidy
 * @since 2024-05-08
 */
@Service
@Slf4j
public class DictDataServiceImpl implements DictDataService {

    private static final Comparator<DictDataDO> COMPARATOR_TYPE_AND_SORT =
            Comparator.comparing(DictDataDO::getDictType).thenComparing(DictDataDO::getSort);

    @Resource
    private DictDataMapper dictDataMapper;

    @Resource
    private DictTypeService dictTypeService;

    /**
     * 获得字典数据列表
     *
     * @param status   状态
     * @param dictType 字典类型
     * @return 字典数据列表
     */
    @Override
    public List<DictDataDO> getDictDataList(Integer status, String dictType) {
        List<DictDataDO> list = dictDataMapper.selectListByStatusAndDictType(status, dictType);
        list.sort(COMPARATOR_TYPE_AND_SORT);
        return list;
    }

    /**
     * 校验字典值是否有效。
     * 以下情况视为无效：
     * 1. 字典数据不存在
     * 2. 字典数据被禁用
     *
     * @param dictType 字典类型
     * @param values   字典值
     */

    @Override
    public void validateDictDataList(String dictType, Collection<String> values) {
        if (CollUtil.isEmpty(values)) {
            return;
        }
        // 将字典数据转为map 其中：key-字典值，value-字典信息
        Map<String, DictDataDO> dictDataDOMap =
                CollectionUtils.convertMap(dictDataMapper.selectByDictTypeAndValues(dictType, values), DictDataDO::getValue);

        // 校验
        values.forEach(value -> {
            DictDataDO dictDataDO = dictDataDOMap.get(value);
            // 字典不存在
            if (dictDataDO == null) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.DICT_DATA_NOT_EXISTS);
            }
            // 字典被禁用
            if (!CommonStatusEnum.ENABLE.getStatus().equals(dictDataDO.getStatus())) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.DICT_DATA_NOT_ENABLE, dictDataDO.getLabel());
            }
        });

    }

    /**
     * 获得指定字典类型的字典数据列表
     *
     * @param dictType 字典类型
     * @return 字典数据列表
     */
    @Override
    public List<DictDataDO> getDictDataListByDictType(String dictType) {
        // 查询获得数据
        List<DictDataDO> dictDataDOS = dictDataMapper.selectList(DictDataDO::getDictType, dictType);
        // 排序
        dictDataDOS.sort(Comparator.comparing(DictDataDO::getSort));
        return dictDataDOS;
    }

    /**
     * 根据字典类型和字典值获得字典信息
     *
     * @param dictType 字典类型
     * @param value    字典值
     * @return 字典信息
     */
    @Override
    public DictDataDO getDictData(String dictType, String value) {
        return dictDataMapper.selectByDictTypeAndValue(dictType, value);
    }

    /**
     * 解析获得指定的字典数据
     *
     * @param dictType 字典类型
     * @param label    字典标签
     * @return 字典信息
     */
    @Override
    public DictDataDO parseDictData(String dictType, String label) {
        return dictDataMapper.selectByDictTypeAndLabel(dictType, label);
    }

    /**
     * 获得字典数据分页列表
     *
     * @param reqVO 查询条件
     * @return 字典数据分页列表
     */
    @Override
    public PageResult<DictDataDO> getDictDataPage(DictDataPageReqVO reqVO) {
        return dictDataMapper.selectPage(reqVO);
    }

    /**
     * 获得字典数据详细信息
     *
     * @param dictId 字典编号
     * @return 字典信息
     */
    @Override
    public DictDataDO getDictData(Long dictId) {
        return dictDataMapper.selectById(dictId);
    }

    /**
     * 创建字典数据
     *
     * @param createReqVO 字典数据信息
     * @return 字典编号
     */
    @Override
    public Long createDictData(DictDataSaveReqVO createReqVO) {
        // 校验字典类型的有效性
        validateDictTypeExists(createReqVO.getDictType());

        // 校验字典数据值的唯一性
        validateDictDataValueUnique(null, createReqVO.getDictType(), createReqVO.getValue());

        // 插入字典数据
        DictDataDO dictData = BeanUtils.toBean(createReqVO, DictDataDO.class);
        dictDataMapper.insert(dictData);
        return dictData.getId();
    }

    /**
     * 修改字典数据
     *
     * @param updateReqVO 字典内容
     */
    @Override
    public void updateDictData(DictDataSaveReqVO updateReqVO) {
        // 校验自己存在
        validateDictDataExists(updateReqVO.getId());

        // 校验字典类型有效
        validateDictTypeExists(updateReqVO.getDictType());

        // 校验字典数据值的唯一性
        validateDictDataValueUnique(updateReqVO.getId(), updateReqVO.getDictType(), updateReqVO.getValue());

        // 更新
        DictDataDO updateObj = BeanUtils.toBean(updateReqVO, DictDataDO.class);
        dictDataMapper.updateById(updateObj);
    }

    /**
     * 删除字典数据
     *
     * @param dictId 字典编号
     */
    @Override
    public void deleteDictData(Long dictId) {
        // 校验是否存在
        validateDictDataExists(dictId);

        // 删除
        dictDataMapper.deleteById(dictId);
    }

    /**
     * 根据字典类型查询字典数据数量
     *
     * @param dictType 字典类型
     * @return 数量
     */
    @Override
    public Long getDictDataCountByDictType(String dictType) {
        return dictDataMapper.selectCount(DictDataDO::getDictType, dictType);
    }

    /**
     * 校验字典是否存在
     *
     * @param dictId 字典编号
     */
    @VisibleForTesting
    private void validateDictDataExists(Long dictId) {
        if (dictId == null) {
            return;
        }
        DictDataDO dictDataDO = dictDataMapper.selectById(dictId);
        if (dictDataDO == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.DICT_DATA_NOT_EXISTS);
        }
    }

    /**
     * 校验字典值的唯一性
     *
     * @param dictId   字典编号
     * @param dictType 字典类型
     * @param value    字典值
     */
    @VisibleForTesting
    private void validateDictDataValueUnique(Long dictId, String dictType, String value) {
        DictDataDO dictDataDO = dictDataMapper.selectByDictTypeAndValue(dictType, value);
        if (dictDataDO == null) {
            return;
        }

        if (dictId == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.DICT_DATA_VALUE_DUPLICATE);
        }
        if (!dictDataDO.getId().equals(dictId)) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.DICT_DATA_VALUE_DUPLICATE);
        }
    }

    /**
     * 校验字典类型的有效性
     *
     * @param dictType 字典类型
     */
    @VisibleForTesting
    private void validateDictTypeExists(String dictType) {
        DictTypeDO dictTypeDO = dictTypeService.getDictType(dictType);
        if (dictTypeDO == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.DICT_TYPE_NOT_EXISTS);
        }

        // 判断是否启用
        if (!CommonStatusEnum.ENABLE.getStatus().equals(dictTypeDO.getStatus())) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.DICT_TYPE_NOT_ENABLE);
        }
    }
}
